﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace Nirvana
{
    /// <summary>
    /// UI渐变
    /// </summary>
    [AddComponentMenu("Nirvana/UI/Effects/Gradient")]
    [RequireComponent(typeof(RectTransform))]
    public sealed class UIGradient : BaseMeshEffect
    {
        public enum GradientMode
        {
            GlobalFullRect,
            Local,
            GlobalTextArea,
        }

        public enum GradientDirection
        {
            Horizontal,
            Vertical  
        }

        public enum ColorMode
        {
            Override,
            Additive,
            Multiply
        }

        [SerializeField]
        private GradientMode gradientMode = GradientMode.Local;
        [SerializeField]
        private GradientDirection gradientDirection = GradientDirection.Horizontal;
        [SerializeField]
        private ColorMode colorMode = ColorMode.Override;
        [SerializeField]
        private Color topColor = Color.white;
        [SerializeField]
        private Color bottomColor = Color.black;
        [SerializeField]
        private bool useGraphicAlpha = true;

#if UNITY_EDITOR
        protected override void OnValidate()
        {
            base.OnValidate();
            if (base.graphic != null) base.graphic.SetVerticesDirty();
        }

#endif

        public override void ModifyMesh(VertexHelper vh)
        {
            if (!this.IsActive() || vh.currentVertCount <= 0)
            {
                return;
            }

            List<UIVertex> tempList = VertexLists.Get();
            vh.GetUIVertexStream(tempList);
            List<UIVertex> newlist = ModifyVertex(tempList);
            if (newlist != null)
            {
                vh.Clear();
                vh.AddUIVertexTriangleStream(newlist);
            }
            VertexLists.Set(newlist);
        }

        private List<UIVertex> ModifyVertex(List<UIVertex> _list)
        {

            if(this.gradientMode == GradientMode.GlobalFullRect || this.gradientMode == GradientMode.GlobalTextArea)
            {
                ModifyTextVertex(_list);
            }
            else
            {
                ModifyOtherVertex(_list);
            }
            return _list;
        }
        private void ModifyOtherVertex(List<UIVertex> _list)
        {
            if (base.graphic is Text)
            {
                this.ModifyOtherVertex1(_list);
            }
            else
            {
                this.ModifyOtherVertex2(_list);
            }
        }

        private void ModifyTextVertex(List<UIVertex> _list)
        {
            Vector2 leftup = Vector2.zero; //左上顶点
            Vector2 rightdown = Vector2.zero;//右下顶点
            if (this.gradientMode == GradientMode.GlobalFullRect) //全范围
            {
                Rect rect = (transform as RectTransform).rect;
                leftup = new Vector2(rect.xMin, rect.yMax);
                rightdown = new Vector2(rect.xMax, rect.yMin);
            }
            else
            {
                leftup = _list[0].position;
                rightdown = _list[_list.Count - 1].position;
                for (int i = 0; i < _list.Count; i++)
                {
                    if (_list[i].position.x < leftup.x)
                    {
                        leftup.x = _list[i].position.x;
                    }
                    if (_list[i].position.y > leftup.y)
                    {
                        leftup.y = _list[i].position.y;
                    }

                    if (_list[i].position.x > rightdown.x)
                    {
                        rightdown.x = _list[i].position.x;
                    }
                    if (_list[i].position.y < rightdown.y)
                    {
                        rightdown.y = _list[i].position.y;
                    }
                }
            }
            float distX = rightdown.x - leftup.x;
            float distY = leftup.y - rightdown.y;

            for (int i = 0; i < _list.Count; i++)
            {
                UIVertex vertex = _list[i];
                if (this.gradientDirection == GradientDirection.Vertical)
                {
                    Color newColor = Color.Lerp(this.topColor, this.bottomColor, (leftup.y - vertex.position.y) / distY);
                    vertex.color = GetColorByColorMode(vertex.color, newColor, this.colorMode);
                }
                else
                {
                    Color newColor = Color.Lerp(this.topColor, this.bottomColor, (vertex.position.x - leftup.x) / distX);
                    vertex.color = GetColorByColorMode(vertex.color, newColor, this.colorMode);
                }
                if (this.useGraphicAlpha)
                {
                    vertex.color.a = (byte)(vertex.color.a * _list[i].color.a / byte.MaxValue);
                }
                _list[i] = vertex;
            }
        }

        private void ModifyOtherVertex1(List<UIVertex> _list)
        {
            for(int i = 0; i < _list.Count; i++)
            {
                UIVertex vertex = _list[i];
                if(this.gradientDirection != GradientDirection.Vertical)
                {
                    if(this.gradientDirection == GradientDirection.Horizontal)
                    {
                        if(i%6 == 0 || i%6==4 || i%6 == 5)
                        {
                            vertex.color = this.GetColorByColorMode(vertex.color, this.topColor, this.colorMode);
                        }
                        else
                        {
                            vertex.color = this.GetColorByColorMode(vertex.color, this.bottomColor, this.colorMode);
                        }
                    }
                }
                else if (i % 6 == 0 || i % 6 == 1 || i % 6 == 5)
                {
                    vertex.color = this.GetColorByColorMode(vertex.color, this.topColor, this.colorMode);
                }
                else
                {
                    vertex.color = this.GetColorByColorMode(vertex.color, this.bottomColor, this.colorMode);
                }

                if (this.useGraphicAlpha)
                {
                    vertex.color.a = (byte)(vertex.color.a * _list[i].color.a / byte.MaxValue);
                }
                _list[i] = vertex;
            }
        }
        private void ModifyOtherVertex2(List<UIVertex> _list)
        {
            for (int i = 0; i < _list.Count; i++)
            {
                UIVertex vertex = _list[i];
                if (this.gradientDirection != GradientDirection.Vertical)
                {
                    if (this.gradientDirection == GradientDirection.Horizontal)
                    {
                        if (i % 6 == 0 || i % 6 == 1 || i % 6 == 5)
                        {
                            vertex.color = this.GetColorByColorMode(vertex.color, this.topColor, this.colorMode);
                        }
                        else
                        {
                            vertex.color = this.GetColorByColorMode(vertex.color, this.bottomColor, this.colorMode);
                        }
                    }
                }
                else if (i % 6 == 1 || i % 6 == 2 || i % 6 == 3)
                {
                    vertex.color = this.GetColorByColorMode(vertex.color, this.topColor, this.colorMode);
                }
                else
                {
                    vertex.color = this.GetColorByColorMode(vertex.color, this.bottomColor, this.colorMode);
                }

                if (this.useGraphicAlpha)
                {
                    vertex.color.a = (byte)(vertex.color.a * _list[i].color.a / byte.MaxValue);
                }
                _list[i] = vertex;
            }
        }
        private Color GetColorByColorMode(Color srcColor,Color destColor, ColorMode colorMode)
        {
            switch (colorMode)
            {
                case ColorMode.Override:
                    return destColor;
                case ColorMode.Additive:
                    return srcColor + destColor;
                case ColorMode.Multiply:
                    return srcColor * destColor;
                default:
                    return destColor;
            }
        }
    }
}

